<?php

namespace App\Models\Traits;

use Carbon\Carbon;
use App\Models\User;
use App\Models\GoldRecord;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Rainsens\Dinglog\Facades\Dinglog;
use Brick\Math\RoundingMode;

trait HasUserStormCache
{	


	public function voucherRecordsCacheKey($cacheId)
	{
		return "{$cacheId}_voucher";
	}

	public function addRecordToVoucherCache($recellCacheId,$cacheId)
	{
		Redis::zAdd($this->voucherRecordsCacheKey($recellCacheId), 1, $cacheId);
		//$count = Redis::zCard($this->voucherRecordsCacheKey($recellCacheId));

		$count = Redis::hGet($recellCacheId,'pending_voucher_num');
		if($count){

			$count = $count+1;
		}else{

			$count = 1;
		}
		
		Redis::hMset($recellCacheId,['pending_voucher_num'=>$count]);

	}


	public static function initGoldRecordsCache()
	{
		/**
		 * Only first deploy.
		 */
		Dinglog::text("============================== User Storm Records Cache Syncing...");
		self::initAllStormCache();
		Dinglog::text("============================== User Storm Records Cache Synced...");
	}

	public static function initAllStormCache()
	{
		self::query()
			->where('is_mock', false)
			->where('is_locked', false)
			->each(function (User $user) {
				$user->syncStormCache();
				Log::info("User: {$user->id} gold records cached.");
			});
	}

	public function syncStormCache()
	{
		if ($this->goldRecords()->exists()) {
			//$this->syncStormUnpaidCache();
			$this->syncStormPendingCache();
			$this->syncStormRunningCache();
			$this->syncStormFinishedCache();
		}
	}

	public function cleanStormUnpaidCache()
	{
		$unpaidCachedIds = Redis::zRange($this->unpaidRecordsCacheKey(), 0, -1);
		if (count($unpaidCachedIds) > 0) {
			foreach ($unpaidCachedIds as $cid) {
				$this->delMyRecordCache($cid);
				Redis::del($this->voucherRecordsCacheKey($cid));
			}
			Redis::del($this->unpaidRecordsCacheKey());
			Log::debug("User: {$this->id} unpaid cache cleaned");
		}
	}

	public function syncStormUnpaidCache()
	{
		$this->cleanStormUnpaidCache();
	}

	public function cleanStormPendingCache()
	{
		$pendingCachedIds = Redis::zRange($this->pendingRecordsCacheKey(), 0, -1);
		if (count($pendingCachedIds) > 0) {
			foreach ($pendingCachedIds as $cid) {
				$this->delMyRecordCache($cid);
				Redis::del($this->voucherRecordsCacheKey($cid));
			}
			Redis::del($this->pendingRecordsCacheKey());
			Log::debug("User: {$this->id} pending cache cleaned");
		}
	}

	public function syncStormPendingCache()
	{
		$this->cleanStormPendingCache();
		GoldRecord::query()->where('user_id', $this->id)
			->inquire('pending')->orderByDesc('id')
			->each(function (GoldRecord $record) {
				if (!$record->isFinished()
					and $record->isSplit()
					and $record->isSplitSettled()) {
					$record->update(['finished_at' => Carbon::now()]);
				}
				if (!$record->is_record_handled
					and $record->hasAppliedToTake()
					and $record->hasAppliedToSplit()) {
					$record->update(['is_record_handled' => true]);
				} else {
					$this->syncRecordToPendingCache($record);
				}
			});
	}

	public function cleanStormRunningCache()
	{
		$runningCachedIds = Redis::zRange($this->runningRecordsCacheKey(), 0, -1);
		if (count($runningCachedIds) > 0) {
			foreach ($runningCachedIds as $cid) {
				$this->delMyRecordCache($cid);
				Redis::del($this->voucherRecordsCacheKey($cid));
			}
			Redis::del($this->runningRecordsCacheKey());
			Log::debug("User: {$this->id} running cache cleaned");
		}
	}

	public function syncStormRunningCache()
	{
		$this->cleanStormRunningCache();
		GoldRecord::query()->where('user_id', $this->id)
			->inquire('running')->orderByDesc('id')
			->each(function (GoldRecord $record) {
				if (!$record->isFinished()
					and $record->isSplit()
					and $record->isSplitSettled()) {
					$record->update(['finished_at' => Carbon::now()]);
				}
				$this->syncRecordToRunningCache($record);
			});
	}

	public function cleanStormFinishedCache()
	{
		$finishedCachedIds = Redis::zRange($this->finishedRecordsCacheKey(), 0, -1);
		if (count($finishedCachedIds) > 0) {
			foreach ($finishedCachedIds as $cid) {
				$this->delMyRecordCache($cid);
				Redis::del($this->voucherRecordsCacheKey($cid));
			}
			Redis::del($this->finishedRecordsCacheKey());
			Log::debug("User: {$this->id} finished cache cleaned");
		}
	}

	public function syncStormFinishedCache()
	{
		$this->cleanStormFinishedCache();
		GoldRecord::query()->where('user_id', $this->id)
			->inquire('finished')->orderByDesc('id')->take(30)->get()
			->each(function (GoldRecord $record) {
				$this->syncRecordToFinishedCache($record);
			});
	}

	public function syncRecordToPendingCache(GoldRecord $record)
	{
		$cacheId = $record->cacheKey();
		$data = $this->syncRecordCacheData($record);
		Redis::zAdd($this->pendingRecordsCacheKey(), 1, $cacheId);
		Redis::hMset($cacheId, $data);

		Log::debug("User: {$record->user_id} GRecord: {$record->id} synced to pending cache");
	}

	public function syncRecordToRunningCache(GoldRecord $record)
	{
		$cacheId = $record->cacheKey();
		$data = $this->syncRecordCacheData($record);
		Redis::zAdd($this->runningRecordsCacheKey(), 1, $cacheId);
		Redis::hMset($cacheId, $data);

		Log::debug("User: {$record->user_id} GRecord: {$record->id} synced to running cache");
	}

	public function syncRecordToFinishedCache(GoldRecord $record)
	{
		$cacheId = $record->cacheKey();
		$data = $this->syncRecordCacheData($record);
		Redis::zAdd($this->finishedRecordsCacheKey(), 1, $cacheId);
		Redis::hMset($cacheId, $data);

		Log::debug("User: {$record->user_id} GRecord: {$record->id} synced to finished cache");
	}

	public function syncRecordCacheData(GoldRecord $record): array
	{
		return [
			'cid' => $record->cacheKey(),
			'user_id' => $record->user_id,
			"user_avatar_url" => img_path($record->user->avatar),
			"user_name" => $record->user->name,
			"user_phone" => $record->user->phone,
			'gold_round_id' => $record->gold_round_id,
			'gold_product_id' => $record->gold_product_id,
			'gold_record_id' => $record->id,
			'record_all_price' => $record->record_all_price,
			'resell_all_price' => $record->resell_all_price,
            'pay_net_price' => $record->pay_net_price,
            'pay_cash_price' => $record->pay_cash_price,
			'pay_gold_beans' => $record->pay_gold_beans,
			'gold_product_is_last_round' => $record->goldProduct->isLastRound(),
			'gold_product_all_price_next' => $record->goldProduct->allPriceNext(),
			'product_title' => $record->goldSeed->product->title,
			'product_cover' => $record->goldSeed->product->cover_url,
			'to_resell_applied_at' => (string)$record->to_resell_applied_at,
			'to_split_applied_at' => (string)$record->to_split_applied_at,
			'to_take_applied_at' => (string)$record->to_take_applied_at,
			'started_at' => (string)$record->started_at,
			'has_applied_to_resell' => $record->hasAppliedToResell(),
			'has_applied_to_split' => $record->hasAppliedToSplit(),
			'has_applied_to_take' => $record->hasAppliedToTake(),
			'splits_all_count' => $record->splitsAllCount(),
			'splits_all_money' => $record->splitsAllMoney(),
			'is_paying' => false,
			'is_paid' => $record->isPaid(),
			'is_resell_applying' => false,
			'is_split_applying' => false,
			'is_take_applying' => false,
			'created_at' => (string)$record->created_at,
			'voucher' =>$record->goldRecordVoucher ?  $record->goldRecordVoucher->voucher : '', 
			'uploaded_at' =>$record->goldRecordVoucher ?  $record->goldRecordVoucher->updated_at : '',
			'is_voucher' =>$record->goldRecordVoucher ?  true : false,
			'is_examine' =>$record->goldRecordVoucher ? $record->goldRecordVoucher->is_examine : '', 
			'is_contact' =>$record->goldRecordVoucher ? $record->goldRecordVoucher->is_contact : '', 
			'product_market_price'=>$record->goldSeed->product->price_market,
			'paid_at'=>$record->paid_at,
			'finished_at'=>$record->finished_at,
		];
	}

	public function myRecordCache($cacheId)
	{
		return Redis::hGetAll($cacheId);
	}

	public function delMyRecordCache($cacheId)
	{
		Redis::del($cacheId);
	}

	public function myRecordsCache($condition): Collection
	{
		$records = collect();

		$cachedIds = [];

		if ($condition == 'unpaid') {
			$cachedIds = Redis::zRevRange($this->unpaidRecordsCacheKey(), 0, -1);
		} elseif ($condition == 'pending') {
			$cachedIds = Redis::zRevRange($this->pendingRecordsCacheKey(), 0, -1);
		} elseif ($condition == 'running') {
			$cachedIds = Redis::zRevRange($this->runningRecordsCacheKey(), 0, -1);
		} elseif ($condition == 'finished') {
			$cachedIds = Redis::zRevRange($this->finishedRecordsCacheKey(), 0, -1);
		}

		if (count($cachedIds) <= 0) return collect();

		foreach ($cachedIds as $cid) {
			$record = $this->myRecordCache($cid);
			if($record){

				$records->push($record);
			}
		
		}

		return $records;
	}

	public function myRecordsCacheCount(): array
	{
		return [
			'unpaid' => Redis::zCard($this->unpaidRecordsCacheKey()),
			'pending' => Redis::zCard($this->pendingRecordsCacheKey()),
			'running' => Redis::zCard($this->runningRecordsCacheKey()),
		];
	}

	public function getUnpaidRecordCacheAllMoney(){
		$result = ['money'=>0, 'rate'=> 0 ,'expired_at'=>Carbon::now()->toDateTimeString()];
		$unpaidArr = Redis::zRange($this->sUnpaidRecordsCacheKey($this->id),0,-1);
		if($unpaidArr){
			foreach($unpaidArr as $v){

				if(Redis::hGet($v,'gold_product_id')){

					if(!$result['rate']){
						$expiredAt =  strtotime(Redis::hGet($v,'paid_expire_at'));
						$createdAt =  strtotime(Redis::hGet($v,'created_at'));
						$nowAt = strtotime(Carbon::now()->toDateTimeString());
						
						$rate = ($nowAt - $createdAt) / ($expiredAt - $createdAt) *100;
						$result['rate'] =  big_decimal($rate)->toScale(2, RoundingMode::HALF_UP);
						if((string)$result['rate'] > 100){
							$result['rate'] = "100";

						}
						$result['expired_at'] = Redis::hGet($v,'paid_expire_at');

					}
					$result['money'] += Redis::hGet($v,'pay_net_price');

					
				}
			}

		}
		$result['money'] = big_decimal($result['money'])->toScale(2, RoundingMode::HALF_UP);

		return $result;
	}


	public function myRecordsExamineCacheCount()
	{
		$cachedIds  = Redis::zRevRange($this->runningRecordsCacheKey(), 0, -1);


		if (count($cachedIds) <= 0) return 0;
		$count = 0;
		foreach ($cachedIds as $cid) {
			$isVoucher = Redis::hGet($cid,'pending_voucher_num');
			if($isVoucher){
				$count +=1;

			}
		}

		return $count;
		
	}

	public function myRecordsCachePage($condition, $fromIndex = 0): Collection
	{
		$records = collect();

		$limit = $fromIndex + 30;
		$cachedIds = [];

		$fromIndex = $fromIndex > 0 ? $fromIndex+1 : $fromIndex;

		if ($condition == 'unpaid') {
			$cachedIds = Redis::zRevRange($this->unpaidRecordsCacheKey(), $fromIndex, $limit);
		} elseif ($condition == 'pending') {
			$cachedIds = Redis::zRevRange($this->pendingRecordsCacheKey(), $fromIndex, $limit);
		} elseif ($condition == 'running') {
			$cachedIds = Redis::zRevRange($this->runningRecordsCacheKey(), $fromIndex, $limit);
		} elseif ($condition == 'finished') {
			$cachedIds = Redis::zRevRange($this->finishedRecordsCacheKey(), $fromIndex, $limit);
		}

		if (count($cachedIds) <= 0) return collect();

		foreach ($cachedIds as $cid) {
			$record = $this->myRecordCache($cid);
			if($record){

				$records->push($record);
			}
		}

		return $records;
	}



	public function myRecordsVoucherCachePage($record): Collection
	{
		$records = collect();

		$cachedIds = Redis::zRevRange($this->voucherRecordsCacheKey($record), 0 , -1);

		if (count($cachedIds) <= 0) return collect();

		foreach ($cachedIds as $cid) {
			$record = $this->myRecordCache($cid);
			if($record){

				$records->push($record);
			}
		}

		return $records;
	}
}
